/* GMServer.cc -- Servidor
 *
 * Copyright (C) 2008, Diogo F. S. Ramos <diogo.ramos@usp.br>
 * GEAR - Grupo de Estudos Avançados em Robótica
 * <http://www.sel.eesc.usp.br/gear>
 *
 * This file is part os GEARMedula.
 * 
 * GEARMedula is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, version 3 of the
 * License.
 * 
 * GEARMedula is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */

//#include <stdio.h>
//#include <errno.h>
//#include <stdlib.h>
//#include <unistd.h>
//#include <sys/types.h>
//#include <sys/socket.h>
#include <netinet/in.h>
//#include <netdb.h>
#include <arpa/inet.h>
//#include <pthread.h>
//#include <string.h>

#include "GMServer.hh"

GMServer::GMServer(void)
{
    socketfd_ = 0;
    XError xerror_();
}


GMServer::~GMServer(void)
{
    
}

void
GMServer::Init( unsigned int port )
{
    CreateSocket( port );

    if(listen( socketfd_, 1 ) < 0 )
	xerror_.Fatal("server:Não consegui me tornar um servidor.");

    /* Iniciando o conjunto de file descriptors */
    FD_ZERO( &active_fd_set_ );
    FD_SET( socketfd_, &active_fd_set_ );
}

void
GMServer::CreateSocket( unsigned int port )
{
    struct sockaddr_in name;
    
    /* Create the socket. */
    socketfd_ = socket (PF_INET, SOCK_STREAM, 0);
    if (socketfd_ < 0)
	xerror_.Fatal("server: Não sonsegui criar um socket.");
     
    /* Give the socket a name. */
    name.sin_family = AF_INET;
    name.sin_port = htons (port);
    name.sin_addr.s_addr = htonl (INADDR_ANY);
    if (bind (socketfd_, (struct sockaddr *) &name, sizeof (name)) < 0)
	xerror_.Fatal("server: Não consegui realizar bind "
		     "no socket recém criado.");
}

void
GMServer::Run( void * ptr )
{
    int i = 0;
    size_t size;
    struct sockaddr_in clientname;

    xerror_.Info("server: Servidor pronto e esperando.");
    while (1)
    {
	/* Block until input arrives on one or more active sockets. */
	read_fd_set_ = active_fd_set_;
	if (select (FD_SETSIZE, &read_fd_set_, NULL, NULL, NULL) < 0)
	    xerror_.Fatal("server: Tive problemas na chamada select");
    

	/* Service all the sockets with input pending. */
	for (i = 0; i < FD_SETSIZE; ++i)
	    if (FD_ISSET (i, &read_fd_set_))
	    {
		if (i == socketfd_)
		{
		    /* Connection request on original socket. */
		    int new_con;
		    size = sizeof (clientname);
		    new_con = accept (socketfd_,
				      (struct sockaddr *) &clientname,
				      &size);
		    if (new_con < 0)
			xerror_.Fatal("server: Problemas em aceitar a conexão"
				     " requisitada");
		    xerror_.Info ( "server: Conexão do host %s, porta %d.",
				  inet_ntoa (clientname.sin_addr),
				  ntohs (clientname.sin_port));
		    FD_SET (new_con, &active_fd_set_);
		}
		else
		{
		    // /* Data arriving on an already-connected socket. */
		    // if (gm_server_read_from_client( self, i) < 0)
		    // {
		    // 	close (i);
		    // 	FD_CLR (i, &(self->active_fd_set));
		    // }
		}
	    }
    }

}
